package org.ee.core.filter;


import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.filter.CommonsRequestLoggingFilter;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 *专门针对 生产环境高效日志，只打印异常请求或慢请求，同时保持美观。
 *
 * 特点如下：
 *
 * 只输出关键 Headers（Content-Type、Authorization、User-Agent）
 *
 * 自动截断 payload，避免日志过长
 *
 * GET 请求打印 query params，POST 请求根据 Content-Type 美化（JSON 或 form-data）
 *
 * 只打印慢请求（响应时间超过阈值）或异常请求（状态码 ≥ 400）
 *
 * 自动掩码 Authorization
 * @Author jokr
 * @Date 2025/8/29 11:38
 */
public class PrettyRequestProdLoggingFilter extends CommonsRequestLoggingFilter {

    private final ObjectMapper objectMapper = new ObjectMapper();

    private static final int MAX_PAYLOAD_LENGTH = 500; // payload 超过截断
    private static final long SLOW_REQUEST_THRESHOLD_MS = 1000; // 慢请求阈值，1秒
    private static final List<String> INCLUDE_HEADERS = Arrays.asList(
            "content-type", "authorization", "user-agent"
    );

    private static final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();

    public PrettyRequestProdLoggingFilter() {
        this.setIncludeQueryString(true);
        this.setIncludePayload(true);
        this.setIncludeHeaders(true);
        this.setIncludeClientInfo(true);
        this.setMaxPayloadLength(4096);
        this.setAfterMessagePrefix("REQUEST DATA-");
    }
    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        startTimeThreadLocal.set(System.currentTimeMillis());
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        long startTime = startTimeThreadLocal.get() != null ? startTimeThreadLocal.get() : 0;
        long duration = System.currentTimeMillis() - startTime;

        // 获取响应状态
        HttpServletResponse response = (HttpServletResponse) request.getAttribute("javax.servlet.error.response");
        int status = response != null ? response.getStatus() : 200;

        // 只打印慢请求或异常请求
        if (duration < SLOW_REQUEST_THRESHOLD_MS && status < 400) {
            return; // 忽略普通请求
        }

        StringBuilder sb = new StringBuilder();
        sb.append("\n=== HTTP REQUEST BEGIN ===\n");
        sb.append("Method : ").append(request.getMethod()).append("\n");
        sb.append("URI    : ").append(request.getRequestURI()).append("\n");
        sb.append("Client : ").append(request.getRemoteAddr()).append("\n");
        sb.append("User   : ").append(request.getRemoteUser()).append("\n");
        sb.append("Duration(ms): ").append(duration).append("\n");
        sb.append("Status: ").append(status).append("\n");

        // Headers
        sb.append("Headers:\n");
        Collections.list(request.getHeaderNames()).forEach(name -> {
            if (INCLUDE_HEADERS.contains(name.toLowerCase())) {
                String value = request.getHeader(name);
                if ("authorization".equalsIgnoreCase(name)) value = maskAuthorization(value);
                sb.append("  ").append(name).append(": ").append(value).append("\n");
            }
        });

        // GET 请求参数
        if ("GET".equalsIgnoreCase(request.getMethod()) && request.getQueryString() != null) {
            sb.append("Query Params:\n  ").append(request.getQueryString()).append("\n");
        }

        // POST 请求 payload
        if ("POST".equalsIgnoreCase(request.getMethod()) && message.contains("payload=")) {
            String payload = message.substring(message.indexOf("payload=") + 8).trim();
            if (payload.endsWith("]")) payload = payload.substring(0, payload.length() - 1);
            if (!payload.isEmpty()) {
                if (payload.length() > MAX_PAYLOAD_LENGTH) {
                    payload = payload.substring(0, MAX_PAYLOAD_LENGTH) + "...(truncated)";
                }
                sb.append("Payload:\n");
                String contentType = request.getContentType();
                if (contentType != null && contentType.contains("application/json")) {
                    try {
                        String pretty = objectMapper.writerWithDefaultPrettyPrinter()
                                .writeValueAsString(objectMapper.readTree(payload));
                        sb.append(pretty).append("\n");
                    } catch (Exception e) {
                        sb.append(payload).append("\n");
                    }
                } else if (contentType != null && contentType.contains("application/x-www-form-urlencoded")) {
                    String[] pairs = payload.split("&");
                    for (String pair : pairs) {
                        sb.append("  ").append(pair.replace("=", " : ")).append("\n");
                    }
                } else {
                    sb.append(payload).append("\n");
                }
            }
        }

        sb.append("=== HTTP REQUEST END ===");
        logger.info(sb.toString());
    }

    private String maskAuthorization(String auth) {
        if (auth == null || auth.length() <= 10) return "****";
        return auth.substring(0, 7) + "****";
    }
}
